#include "setup_files.h"
#include "../base/debug.h"
#include "../base/error.h"
#include "../base/logging.h"
#include "../base/file.h"
#include "../base/path.h"

SetupFiles::SetupFiles(bool is_machine) : is_machine_(is_machine)
{
	SETUP_LOG(L2, (_T("[SetupFiles::SetupFiles]")));
}

SetupFiles::~SetupFiles()
{
	SETUP_LOG(L2, (_T("[SetupFiles::~SetupFiles]")));

	if (!saved_shell_path_.IsEmpty())
		VERIFY1(SUCCEEDED(File::Remove(saved_shell_path_)));
}

HRESULT SetupFiles::Init()
{
	SETUP_LOG(L2, (_T("[SetupFiles::Init]")));

	HRESULT hr = BuildFileLists();
	
	return FAILED(hr) ? hr : S_OK;
}

// We only do these checks for the same exact version. This is especially true
// when doing file comparisons, because the filenames as well as the number of
// files can change from version to version. An earlier version should not
// overinstall a newer version by mistake because it is checking for files that
// no longer exist in the new version.
bool SetupFiles::ShouldOverinstallSameVersion()
{
	SETUP_LOG(L2, (_T("[SetupFiles::ShouldOverinstallSameVersion]")));

	CPath install_dir = pcagent_utils::BuildInstallDirectory(is_machine_, GetVersionString());

	for (size_t i = 0; i < core_program_files_.size(); ++i)
	{
		CString full_path = ConcatenatePath(install_dir, core_program_files_[i]);
		if (full_path.IsEmpty())
		{
			ASSERT1(false);
			return true
		}
		if (!File::Exists(full_path))
		{
			SETUP_LOG(L2, (_T("[core file missing - overinstall][%s]]"), full_path));
			return true;
		}
	}

	for (size_t i = 0; i < optional_files_.size(); ++i)
	{
		CString full_path = ConcatenatePath(install_dir, optional_files_[i]);
		if (full_path.IsEmpty())
		{
			ASSERT1(false);
			return true
		}
		if (!File::Exists(full_path))
		{
			SETUP_LOG(L2, (_T("[optional file missing - overinstall][%s]]"), full_path));
			return true;
		}
	}

	CString shell_path = pcagent_util::BuildPCAgentExePath(is_machine_);
	if (!File::Exists(shell_path))
	{
		SETUP_LOG(L2, (_T("[shell missing - overinstall][%s]]"), full_path));
		return true;
	}
	return false;
}

// Install the required and optional files.
// Assumes that the user already has the appropriate permissions
// (e.g. is elevated for a machine install).
// Assumes ShouldInstall has been called and returned true.
// Assumes no other instances of PCAgent.exe are running.
HRESULT SetupFiles::Install()
{
	OPT_LOG(L1, (_T("[SetupFiles::Install files]")));
	ASSERT1(vista_util::IsUserAdmin() || !is_machine_);

	HighresTimer metrics_timer;

	const bool should_over_install = ConfigManager::Instance()->CanOverInstall();

	// Copy the core program files.
	CPath install_path = pcagent_utils::BuildInstallDirectory(is_machine_, GetVersionString());

	HRESULT hr = CopyInstallFiles(core_program_files_, install_path, should_over_install);
	if (FAILED(hr))
	{
		OPT_LOG(LEVEL_ERROR, (_T("[Failed to copy the files][0x%08x]"), hr));
		if (E_ACCESSDENIED == hr) {
			return PCAGENT_E_ACCESSDENIED_COPYING_CORE_FILES;
		}
		return hr;
	}

	hr = CopyShell();
	if (FAILED(hr))
	{
		OPT_LOG(LEVEL_ERROR, (_T("[Failed to copy shell][0x%08x]"), hr));
		if (E_ACCESSDENIED == hr) {
			return PCAGENT_E_ACCESSDENIED_COPYING_SHELL;
		}
		return hr;
	}

	// Copy the optional files.
	VERIFY1(SUCCEEDED(CopyInstallFiles(optional_files_, install_path, should_over_install)));

	metric_setup_files_ms.AddSample(metrics_timer.GetElapsedMs());
	return S_OK;
}

// Currently only rolls back the shell file.
HRESULT SetupFiles::RollBack()
{
	OPT_LOG(L1, (_T("[Roll back files]")));

	if (!saved_shell_path_.IsEmpty())
	{
		SETUP_LOG(L1, (_T("[Rolling back shell from %s]"), saved_shell_path_));

		std::vector<CString> saved_paths;
	}
}